import sys

from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5 import Qt
from PyQt5 import QtCore
from PyQt5 import QtGui

from Generator import Grade1, Grade2, Grade3
from User import usersystem
from UI.MainWindowUI import Ui_MainWindow
from UI.loginUI import Ui_Login
from UI.WrongAnswerUI import Ui_WrongAnswer

# 主窗口类
class Main(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(Main, self).__init__()
        # 读取UI文件
        self.setWindowIcon(QIcon('./Icon/questions.svg'))
        self.setupUi(self)
        self.difficulty = 1                 # 默认难度简单
        self.type = 1                       # 默认类型填空题
        self.rightCnt = 0                   # 初始题目数为0
        self.usersys = usersystem()         # 创建用户管理系统
        self.usersys.initialization()       # 用户管理系统初始化
        self.usersys.loadfile_user()        # 用户信息读取
        self.usersys.loadfile_anssys()
        self.usersys.loadfile_wrongans()    # 读取错题
        self.usersys.loadfile_wrongans2()
        self.initUi()                       # 初始化Ui

    # 配置UI，设置信号与槽
    def initUi(self):
        # 输入框设置
        self.fill_answer_edit.setPlaceholderText('输入运算结果')
        self.fill_answer_edit.setValidator(QIntValidator())     # 限制输入为整数
        self.fill_answer_edit.editingFinished.connect(self.ansCheck)

        # # 确定按钮设置
        self.fill_confirm_btn.toggled.connect(self.ansCheck)      # 修复了clicked似乎按下和释放都会触发的BUG
        self.choose_confirm_btn.clicked.connect(self.ansCheck)
        self.decide_confirm_btn.clicked.connect(self.ansCheck)

        # 菜单栏分组
        self.gradeGroup = QActionGroup(self)
        self.gradeGroup.addAction(self.action_Grade1)
        self.gradeGroup.addAction(self.action_Grade2)
        self.gradeGroup.addAction(self.action_Grade3)

        self.difficultyGroup = QActionGroup(self)
        self.difficultyGroup.addAction(self.action_easy)
        self.difficultyGroup.addAction(self.action_mid)
        self.difficultyGroup.addAction(self.action_hard)

        self.typeGroup = QActionGroup(self)
        self.typeGroup.addAction(self.action_fill)
        self.typeGroup.addAction(self.action_choose)
        self.typeGroup.addAction(self.action_decide)
        self.typeGroup.addAction(self.action_exam)

        # 菜单栏修改年级
        self.action_Grade1.triggered.connect(lambda: self.createGrade())
        self.action_Grade2.triggered.connect(lambda: self.createGrade())
        self.action_Grade3.triggered.connect(lambda: self.createGrade())

        # 修改难度
        self.action_easy.triggered.connect(lambda: self.changeDifficulty(1))
        self.action_mid.triggered.connect(lambda: self.changeDifficulty(2))
        self.action_hard.triggered.connect(lambda: self.changeDifficulty(3))

        # 修改题型
        self.action_fill.triggered.connect(self.changeType)
        self.action_choose.triggered.connect(self.changeType)
        self.action_decide.triggered.connect(self.changeType)

        # 登陆
        self.action_login.triggered.connect(self.userLogin)

        # 当前用户
        self.action_currentUser.triggered.connect(self.userCurrent)

        # 登出
        self.action_logout.triggered.connect(self.userLogout)

        # 检查更新
        self.action_update.triggered.connect(self.detectUpdate)

        # 关于
        self.action_about.triggered.connect(self.showAboutDialog)

        # 计时器配置
        self.time = QtCore.QTimer(self)
        self.curTime = QtCore.QTime(0,0,0)      # 从0开始计时
        self.time.timeout.connect(self.showTime)
        self.time.start(1000)

        # 错题窗口显示
        self.wrongAnsWindow = WrongAnsWindow(self)
        self.action_wrongAnswer.triggered.connect(self.showWrongAns)
        self.newWrong = False       # 记录本次运行程序是否有错题

        # 用户登陆窗口显示
        self.login = LoginWindow(self)      # 用户登陆
        self.createGrade()                  # 初始化年级

        self.show()

    # 创建年级类实例
    # i=0表示信号来自多选框，i>0表示信号来自菜单栏
    def createGrade(self):
        # print("创建年级,type = " + str(self.type))
        if self.action_Grade1.isChecked():      # 一年级
            self.curGrade = Grade1.Gradeone(self.difficulty, self.type)
            self.fill_grade_label.setText("一年级")
            self.choose_grade_label.setText("一年级")
            self.decide_grade_label.setText("一年级")
        elif self.action_Grade2.isChecked():
            self.curGrade = Grade2.Gradetwo(self.difficulty, self.type)
            self.fill_grade_label.setText("二年级")
            self.choose_grade_label.setText("二年级")
            self.decide_grade_label.setText("二年级")
        else:
            self.curGrade = Grade3.Gradethree(self.difficulty, self.type)
            self.fill_grade_label.setText("三年级")
            self.choose_grade_label.setText("三年级")
            self.decide_grade_label.setText("三年级")

        self.createQuestion()
        self.rightCnt = 0                       # 计算每一轮完成的题目
        self.wrongCnt = 0                       # 计算错题数
        self.wrongFlag = False
        self.fill_result_label.setText("未输入回答")
        self.fill_num_label.setText("0 道题")
        self.choose_result_label.setText("未输入回答")
        self.choose_num_label.setText("0 道题")
        self.decide_result_label.setText("未输入回答")
        self.decide_num_label.setText("0 道题")

        self.curTime.setHMS(0,0,0,0)        # 从0开始计时
        self.fill_timer_label.setText("00:00:00")
        self.choose_timer_label.setText("00:00:00")
        self.decide_timer_label.setText("00:00:00")

    # 修改难度
    def changeDifficulty(self, d=1):
        if d == 1:
            self.fill_difficulty_label.setText('简单')
            self.choose_difficulty_label.setText('简单')
            self.decide_difficulty_label.setText('简单')
        elif d == 2:
            self.fill_difficulty_label.setText('中等')
            self.choose_difficulty_label.setText('中等')
            self.decide_difficulty_label.setText('中等')
        else:
            self.fill_difficulty_label.setText('困难')
            self.choose_difficulty_label.setText('困难')
            self.decide_difficulty_label.setText('困难')
        self.difficulty = d
        self.createGrade()

    # 修改题型
    def changeType(self):
        if self.action_fill.isChecked():
            self.type = 1
            self.stackedWidget.setCurrentIndex(0)
            self.createGrade()
        elif self.action_choose.isChecked():
            self.type = 2
            self.stackedWidget.setCurrentIndex(1)
            self.createGrade()
        elif self.action_decide.isChecked():
            self.type = 3
            self.stackedWidget.setCurrentIndex(2)
            self.createGrade()

    # 生成题目并显示
    def createQuestion(self):
        if self.rightCnt > 0 and self.rightCnt % 20 == 0:
            self.showCourage()
        self.curGrade.calculationgeneration()
        expression, ans, opt, key = self.curGrade.get_shuffle()
        if self.type == 1:      # 填空题
            self.fill_textBrowser.setText(expression + '?')
            self.ans = ans
        elif self.type == 2:    # 选择题
            self.choose_textBrowser.setText(expression + '?')
            option = "A." + str(opt[0]) + "  B." + str(opt[1]) + "  C." + str(opt[2]) + "  D." + str(opt[3])
            self.choose_textBrowser.append(option)
            self.ans = key
        elif self.type == 3:    # 判断题
            self.decide_textBrowser.setText(expression + str(opt) + ' ?')
            self.ans = key
        self.mistake = False    # 记录本题是否做错

    # 检查结果是否正确
    def ansCheck(self):
        # print("检查结果")
        if self.type == 1:      # 填空题
            inputStr = self.fill_answer_edit.text()
            try:
                ansInput = int(inputStr)
                if(ansInput == self.ans):
                    self.fill_result_label.setText("√ 正确");
                    self.fill_answer_edit.clear()
                    self.rightCnt = self.rightCnt + 1
                    self.fill_num_label.setText(str(self.rightCnt) + " 道题")
                    self.wrongFlag = False
                    self.createQuestion()
                else:
                    self.fill_result_label.setText("× 错误")
                    self.newWrong = True
                    print("错误")
                    if self.wrongFlag == False:
                        self.wrongCnt += 1
                        self.wrongFlag = True
                    # 记录错题，并保证不重复记录错题
                    if self.mistake == False:
                        date = QtCore.QDate.currentDate().toString("yyyy-MM-dd")
                        self.usersys.wrongans_update((date, self.difficulty, [self.curGrade.get_str()]))
                        print("记录错题：" + str([self.curGrade.get_str()]))
                        self.mistake = True
            except:
                self.fill_result_label.setText('未输入回答')   # 当字符串为空或其他格式错误时触发
        elif self.type == 2:    # 选择题
            if self.ans == 'A' and self.chooseA_btn.isChecked() or self.ans == 'B' and self.chooseB_btn.isChecked()\
                or self.ans == 'C' and self.chooseC_btn.isChecked() or self.ans == 'D' and self.chooseD_btn.isChecked():
                self.choose_result_label.setText("√ 正确")
                self.rightCnt = self.rightCnt + 1
                self.choose_num_label.setText(str(self.rightCnt) + " 道题")
                self.wrongFlag = False
                self.createQuestion()
            else:
                self.choose_result_label.setText("× 错误")
                self.newWrong = True
                if self.wrongFlag == False:
                    self.wrongCnt += 1
                    self.wrongFlag = True
                # 记录错题，并保证不重复记录错题
                if self.mistake == False:
                    date = QtCore.QDate.currentDate().toString("yyyy-MM-dd")
                    self.usersys.wrongans_update((date, self.difficulty, [self.curGrade.get_str()]))
                    self.mistake = True
        elif self.type == 3:
            if self.ans == True and self.decideYes_btn.isChecked() or self.ans == False and self.decideNo_btn.isChecked():
                self.decide_result_label.setText("√ 正确")
                self.rightCnt = self.rightCnt + 1
                self.decide_num_label.setText(str(self.rightCnt) + " 道题")
                self.wrongFlag = False
                self.createQuestion()
            else:
                self.decide_result_label.setText("× 错误")
                self.newWrong = True
                if self.wrongFlag == False:
                    self.wrongCnt += 1
                    self.wrongFlag = True
                # 记录错题，并保证不重复记录错题
                if self.mistake == False:
                    date = QtCore.QDate.currentDate().toString("yyyy-MM-dd")
                    self.usersys.wrongans_update((date, self.difficulty, [self.curGrade.get_str()]))
                    self.mistake = True

    # 生成“关于”对话框
    def showAboutDialog(self):
        QMessageBox.about(self, "关于", "<html><head/><body><p><span style=' font-size:12pt;'>"
                                      "小学生算数练习桌面客户端</span></p></body></html>" +
                            "<p>版本1.0 (win32-x64) [CN]</p><p>Copyright @2019-2019</p>")

    # 生成“检查更新”对话框
    def detectUpdate(self):
        QMessageBox.about(self, "检查更新", "<html><head/><body><p><span style=' font-size:12pt;'>"
                                      "小学生算数练习桌面客户端</span></p></body></html>" +
                          "<p>已经是最新版本：v1.0</p>")

    # 登陆对话框
    def userLogin(self):
        self.login.show()

    # 注册对话框
    def userRegister(self):
        text, ok = QInputDialog.getText(self, '注册', '请输入用户名：')
        while (ok and len(text) == 0):  # 用户没有输入
            text, ok = QInputDialog.getText(self, '注册', '请重新输入用户名：')
        if ok:
            print(text + "注册成功")

    # 显示当前用户
    def userCurrent(self):
        dialog = QDialog()
        dialog.resize(150, 80)
        if len(self.usersys.current_user) == 0:
            username = "游客"
        else:
            username = self.usersys.current_user
        label_user = QLabel("\n     当前用户：" + username, dialog)
        button_user = QPushButton("确定", dialog)
        button_user.clicked.connect(dialog.close)
        button_user.move(40, 50)
        dialog.setWindowTitle("当前用户")
        dialog.exec()

    # 返回当前用户名
    def getUsername(self):
        if len(self.usersys.current_user) == 0:
            return "游客"
        else:
            return self.usersys.current_user

    # 登出当前用户，变为游客
    def userLogout(self):
        dialog = QDialog()
        dialog.resize(150, 80)
        if len(self.usersys.current_user) == 0:
            username = "游客"
            label_user = QLabel("\n       登出失败\n  当前未登录，无法登出", dialog)
            button_user = QPushButton("确定", dialog)
            button_user.clicked.connect(dialog.close)
            button_user.move(40, 50)
            dialog.setWindowTitle("登出")
            self.usersys.current_user = ""
            dialog.exec()
        else:
            username = self.usersys.current_user
            label_user = QLabel("       登出成功\n      原用户：" + username + "\n 当前用户变为：游客", dialog)
            button_user = QPushButton("确定", dialog)
            button_user.clicked.connect(dialog.close)
            button_user.move(40, 50)
            dialog.setWindowTitle("登出")
            self.usersys.current_user = ""
            dialog.exec()

    # 计时器
    def showTime(self):
        # print("计时")
        self.curTime = self.curTime.addSecs(1)     # 这个方法并不改变自身
        self.fill_timer_label.setText(self.curTime.toString("hh:mm:ss"))
        self.choose_timer_label.setText(self.curTime.toString("hh:mm:ss"))
        self.decide_timer_label.setText(self.curTime.toString("hh:mm:ss"))

    # 显示错题窗口
    def showWrongAns(self):
        if len(self.usersys.current_user) == 0:
            QMessageBox.information(self, '当前身份：游客', '游客身份无法访问错题，请登录！', QMessageBox.Ok)
            return
        else:
            self.wrongAnsWindow.setUsername()
            self.wrongAnsWindow.showWrong()
            self.wrongAnsWindow.show()

    # 显示激励窗口
    def showCourage(self):
        percentage = round(100 * (1 - self.wrongCnt / self.rightCnt), 2)
        if percentage < 60:
            QMessageBox.information(self, '别灰心！' + self.getUsername(), '你已经完成了' + str(self.rightCnt) + \
                                    '道题\n正确率为' + str(percentage) + '%\n再加把劲，相信自己！', QMessageBox.Ok)
        else:
            QMessageBox.information(self, '加油！' + self.getUsername(), '你已经完成了' + str(self.rightCnt) + \
                                '道题\n正确率为' + str(percentage) +'%\n请继续努力！', QMessageBox.Ok)

    # 重写窗口关闭
    def closeEvent(self, event):
        if not self.newWrong:       # 如果没有错题，则直接关闭
            event.accept()
            return;
        reply = QMessageBox.question(self, '本程序',"是否要保存错题？",\
                QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel,QMessageBox.Yes)
        if reply == QMessageBox.Cancel:
            event.ignore()
        else:
            if reply == QMessageBox.Yes:        # 保存错题
                self.usersys.writefile_wrongans()
            event.accept()

# 登陆窗口
class LoginWindow(QWidget, Ui_Login):
    def __init__(self, mainWindow: Main):
        super(LoginWindow, self).__init__()
        self.mainWindow = mainWindow
        self.setupUi(self)
        self.setWindowIcon(QIcon('./Icon/questions.svg'))
        self.initUI()

    def initUI(self):
        self.setWindowModality(QtCore.Qt.ApplicationModal)  # 设置阻塞

        # 设置过滤器，限制输入格式，只能大小写字母、数字和下划线
        my_regex = QtCore.QRegExp("[a-zA-Z0-9_]+")
        my_validator = QtGui.QRegExpValidator(my_regex)

        # 登陆界面设置
        self.login_btn.clicked.connect(self.tryLogin)
        self.login_btn.setShortcut(QtCore.Qt.Key_Return)    # 设置回车即可登陆
        self.stackedWidget.setCurrentIndex(0)               # 显示登陆界面
        self.register_btn.clicked.connect(lambda: self.stackedWidget.setCurrentIndex(1))
        self.forget_btn.clicked.connect(lambda :self.stackedWidget.setCurrentIndex(2))
        self.username_edit.setValidator(my_validator)
        self.password_edit.setValidator(my_validator)

        # 注册界面设置
        self.return_btn.clicked.connect(lambda :self.stackedWidget.setCurrentIndex(0))
        self.register_username_edit.setValidator(my_validator)
        self.register_password_edit.setValidator(my_validator)
        self.try_register_btn.setShortcut(QtCore.Qt.Key_Return)
        self.try_register_btn.clicked.connect(self.tryRegister)

        # 修改密码界面设置
        self.return_btn2.clicked.connect(lambda: self.stackedWidget.setCurrentIndex(0))
        self.register_username_edit_2.setValidator(my_validator)
        self.register_password_edit_2.setValidator(my_validator)
        self.try_register_btn_2.setShortcut(QtCore.Qt.Key_Return)
        self.try_register_btn_2.clicked.connect(self.tryModify)

        # 第一次运行时显示登陆界面
        self.show()

    # 用户登录
    def tryLogin(self):
        state = self.mainWindow.usersys.userlogin((self.username_edit.text(), self.password_edit.text()))
        if state == -1:
            self.wrong_label.setText("用户名错误")
        elif state == 0:
            self.wrong_label.setText("密码错误")
        else:
            self.wrong_label.setText("登陆成功")
            self.username_edit.clear()
            self.password_edit.clear()
            self.close()

    # 注册新用户
    def tryRegister(self):
        # 初始化
        self.wrong_password_label.clear()
        self.wrong_confirm_label.clear()
        self.wrong_name_label.clear()
        self.empty_ans_label.clear()

        # 检验两次密码和回答
        if self.register_password_edit.text() != self.confirm_password_edit.text():
            self.wrong_password_label.setText("两次密码不一致")
            self.wrong_confirm_label.setText("两次密码不一致")
            return
        elif len(self.answer_edit.text()) == 0:
            self.empty_ans_label.setText("回答不能为空")
            return

        # 判断能否注册用户
        state = self.mainWindow.usersys.accountcreate((self.register_username_edit.text(), self.register_password_edit.text(), self.answer_edit.text()))
        if state == 0:
            self.wrong_name_label.setText("用户名已存在")
        else:
            self.wrong_label.setText("注册成功，用户名：" + self.register_username_edit.text())
            self.register_username_edit.clear()
            self.register_password_edit.clear()
            self.confirm_password_edit.clear()
            self.answer_edit.clear()
            self.wrong_password_label.clear()
            self.wrong_confirm_label.clear()
            self.wrong_name_label.clear()
            self.empty_ans_label.clear()
            self.mainWindow.usersys.writefile_user()        # 保存用户信息到本地
            self.mainWindow.usersys.writefile_anssys()      # 保存回答
            self.stackedWidget.setCurrentIndex(0)           # 回到登陆界面

    # 修改密码
    def tryModify(self):
        # 初始化
        self.wrong_password_label_2.clear()
        self.wrong_confirm_label_2.clear()
        self.wrong_name_label_2.clear()
        self.wrong_ans_label.clear()

        # 检验两次密码和回答
        if self.register_password_edit_2.text() != self.confirm_password_edit_2.text():
            self.wrong_password_label_2.setText("两次密码不一致")
            self.wrong_confirm_label_2.setText("两次密码不一致")
            return
        elif len(self.answer_edit_2.text()) == 0:
            self.wrong_ans_label.setText("回答不能为空")
            return

        # 判断用户名和答案是否匹配
        pw = self.mainWindow.usersys.findpass(self.register_username_edit_2.text(), self.answer_edit_2.text())
        if pw == '-1':
            self.wrong_name_label_2.setText("用户名不存在")
            return
        elif pw == '-a':
            self.wrong_ans_label.setText("答案错误")
            return

        # 修改密码
        state = self.mainWindow.usersys.password_adj((self.register_username_edit_2.text(), pw), self.register_password_edit_2.text())
        if state == -1:
            self.wrong_name_label_2.setText("用户名不存在")
        elif state == 0:
            self.wrong_ans_label.setText("回答错误")
        else:
            self.wrong_label.setText("修改成功，用户名：" + self.register_username_edit_2.text())
            self.register_username_edit_2.clear()
            self.register_password_edit_2.clear()
            self.confirm_password_edit_2.clear()
            self.answer_edit_2.clear()
            self.stackedWidget.setCurrentIndex(0)        # 回到登陆界面

# 错题窗口
class WrongAnsWindow(QWidget,Ui_WrongAnswer):
    def __init__(self, mainWindow: Main):
        super(WrongAnsWindow, self).__init__()
        self.mainWindow = mainWindow
        self.setupUi(self)
        self.setWindowIcon(QIcon('./Icon/questions.svg'))
        self.initUI()

    def initUI(self):
        self.setWindowModality(QtCore.Qt.ApplicationModal)  # 设置阻塞

        # 初始化错题为空
        self.wrongAnsList = ['本日无错题']
        self.answer = []
        self.listModel = QtCore.QStringListModel()
        self.listModel.setStringList(self.wrongAnsList)
        self.listView.setModel(self.listModel)
        self.listView.setEditTriggers(QAbstractItemView.NoEditTriggers)

        # 设置日历点击事件
        self.calendarWidget.clicked.connect(self.showWrong)

        # 设置错题列表点击事件
        self.listView.clicked.connect(self.showDetail)
        self.currentRow = -1

        # 设置按钮点击事件
        self.last_btn.clicked.connect(lambda :self.changeDetail(-1))
        self.next_bnt.clicked.connect(lambda :self.changeDetail(1))
        self.goBack_btn.clicked.connect(lambda :self.stackedWidget.setCurrentIndex(0))
        self.toolButton.clicked.connect(lambda :self.lineEdit.setEchoMode(QLineEdit.Normal))

        self.stackedWidget.setCurrentIndex(0)

    # 显示当前用户
    def setUsername(self):
        self.current_user_label.setText("当前用户：" + self.mainWindow.getUsername())

    # 显示当日错题
    def showWrong(self):
        date = self.calendarWidget.selectedDate().toString("yyyy-MM-dd")
        # print(date)
        walist = self.mainWindow.usersys.wrongans_achieve(date)     # 获取错题列表
        if len(walist) == 0:
            self.wrongAnsList = ['本日无错题']
            self.answer = []
        else:
            self.wrongAnsList, self.answer = zip(*walist)
        self.listModel.setStringList(self.wrongAnsList)

    # 查看详细信息
    def showDetail(self, item):
        if len(self.answer) == 0:
            self.currentRow = -1
            return
        self.currentRow = item.row()
        self.textBrowser.setText(self.wrongAnsList[self.currentRow])

        self.last_btn.setEnabled(True)
        self.next_bnt.setEnabled(True)
        if self.currentRow == 0:
            self.last_btn.setEnabled(False)
        if self.currentRow == len(self.wrongAnsList) - 1:
            self.next_bnt.setEnabled(False)

        self.lineEdit.setText(str(self.answer[self.currentRow]))
        self.lineEdit.setEchoMode(QLineEdit.Password)

        self.stackedWidget.setCurrentIndex(1)

    # 查看前后错题
    def changeDetail(self, flag):
        self.next_bnt.setEnabled(True)
        self.last_btn.setEnabled(True)

        if flag == 1:
            if self.currentRow + 1 >= len(self.wrongAnsList):
                self.next_bnt.setEnabled(False)
                return
            self.currentRow = self.currentRow + 1
            self.textBrowser.setText(self.wrongAnsList[self.currentRow])
            self.lineEdit.setText(str(self.answer[self.currentRow]))
        elif flag == -1:
            if self.currentRow == 0:
                self.last_btn.setEnabled(False)
                return
            self.currentRow = self.currentRow - 1
            self.textBrowser.setText(self.wrongAnsList[self.currentRow])
            self.lineEdit.setText(str(self.answer[self.currentRow]))

        if self.currentRow == 0:
            self.last_btn.setEnabled(False)
        if self.currentRow == len(self.wrongAnsList) - 1:
            self.next_bnt.setEnabled(False)

        self.lineEdit.setEchoMode(QLineEdit.Password)


# 生成并运行主窗口
if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = Main()
    sys.exit(app.exec_())